using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;



using Camera;
using Drawing;
using Input;
using Interface;
using Entities;
using Terrain;
using Particles;
using Base;
namespace Engine
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Engine : Microsoft.Xna.Framework.Game
    {

        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        ContentManager content;
        WindowManager windowManager;
        Drawing2DManager drawing2DManager;
        Drawing3DManager drawing3DManager;


        public Engine()
        {
            IsMouseVisible = true;
            graphics = new GraphicsDeviceManager(this);
            graphics.MinimumPixelShaderProfile = ShaderProfile.PS_2_0;
            Content.RootDirectory = "Content";
        }

        private void ChangeRes()
        {
            GameInformation.GraphicsManager.IsFullScreen = GameInformation.Configuration.Fullscreen;
            GameInformation.GraphicsManager.PreferredBackBufferWidth = GameInformation.Configuration.Width;
            GameInformation.GraphicsManager.PreferredBackBufferHeight = GameInformation.Configuration.Height;
            GameInformation.GraphicsManager.ApplyChanges();
            drawing2DManager.UpdateScreen();
            GameInformation.ResChanged = false;
        }


        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            content = new ContentManager(Services);


            CameraComponent cameraComponent = new CameraComponent(this);
            cameraComponent.Position = new Vector3(0.0f, 0.0f, 0.0f);
            cameraComponent.LookAt(new Vector3());
            cameraComponent.OrbitOffsetDistance = 50.0f;
            cameraComponent.OrbitMaxZoom = 100.0f;
            cameraComponent.OrbitMinZoom = 10.0f;
            cameraComponent.MouseWheelSpeed = 10.0f;
            this.Components.Add(cameraComponent);
            Services.AddService(typeof(ICameraService), cameraComponent);
            cameraComponent.Rotate(-110.0f, -60.0f, 0.0f);

            ParticleController particleController = new ParticleController(this);
            particleController.DrawOrder = 5;
            Components.Add(particleController);
            Services.AddService(typeof(IParticleController), particleController);

            drawing2DManager = new Drawing2DManager(this);
            drawing2DManager.DrawOrder = 4;
            Services.AddService(typeof(IDrawing2DManager), drawing2DManager);
            this.Components.Add(drawing2DManager);

            drawing3DManager = new Drawing3DManager(this);
            drawing3DManager.DrawOrder = 5;
            Services.AddService(typeof(IDrawing3DManager), drawing3DManager);
            this.Components.Add(drawing3DManager);

            Services.AddService(typeof(IInputControllerService), new InputController());
            MouseController mouseController = new MouseController(this);
            mouseController.DrawOrder = 2;
            Components.Add(mouseController);


            EntityController entityController = new EntityController(this);
            entityController.DrawOrder = 3;
            Components.Add(entityController);
            Services.AddService(typeof(IEntityController), entityController);


            TerrainController terrain = new TerrainController(this);
            Components.Add(terrain);
            Services.AddService(typeof(ITerrainController), terrain);
            

            base.Initialize();

            List<string> keys = new List<string>();
            foreach (string key in entityController.ActorTypes.Keys)
            {
                keys.Add(key);
            }

            windowManager = new WindowManager(this, graphics, keys);
            GameInformation.GraphicsManager = graphics;
            GameInformation.Game = this;
            ChangeRes();
            windowManager.ChangeRes();


            
        }



        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here

        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            IInputControllerService input = (IInputControllerService)Services.GetService(typeof(IInputControllerService));
            IEntityController entities = (IEntityController)Services.GetService(typeof(IEntityController));

            GameInformation.UnitCount = entities.Actors.Count;
            if (GameInformation.ResChanged)
            {
                ChangeRes();
                windowManager.ChangeRes();
            }

            if (input.Escape)
            {
                this.Exit();
            }

            windowManager.Update(gameTime, Window);
            base.Update(gameTime);
        }



        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            ICameraService camera = (ICameraService)Services.GetService(typeof(ICameraService));


            ////Draw Grid
            GraphicsDevice.RenderState.DepthBufferEnable = true;
            GraphicsDevice.RenderState.AlphaBlendEnable = false;
            GraphicsDevice.RenderState.AlphaTestEnable = false;

            base.Draw(gameTime);
            windowManager.Draw(gameTime);
        }
    }
}
